package com.jh.loadbalance.client.custom.rest;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * @author Administrator
 * @projectName newforward
 * @title
 * @package com.jh.loadbalance.client.custom.rest
 * @description
 * @date 2019/8/26 22:24
 */
public class MappingMethodInvocationHandler implements InvocationHandler {

    private final BeanFactory beanFactory;

    private final String serviceName;

    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    public MappingMethodInvocationHandler(BeanFactory beanFactory, String serviceName) {
        this.beanFactory = beanFactory;
        this.serviceName = serviceName;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 获取方法上的 @RequestMapping 元信息
        GetMapping requestMapping = AnnotationUtils.findAnnotation(method, GetMapping.class);

        // todo URI（暂时只拿第一个）
        String[] uris = requestMapping.value();
        String uri = uris[0];

        // 参数拼接
        StringBuilder urlBuilder = new StringBuilder("http://").append(serviceName).append(uri);

        // 获取参数名称
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        if (null != parameterNames && parameterNames.length > 0) {
            // 获取参数类型
            Class<?>[] parameterTypes = method.getParameterTypes();
            // 参数个数
            int parameterCount = method.getParameterCount();
            // paramAnnotations
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();

            Stream.iterate(0, i -> i + 1).limit(parameterCount).forEach(i -> {

                Class<?> type = parameterTypes[i];
                String name = "";

                // 获取参数上的注解
                Annotation paramAnnotation = Stream.of(parameterAnnotations[i])
                        .filter(annotation -> annotation instanceof RequestParam || annotation instanceof PathVariable)
                        .findFirst().orElse(null);

                // 拼接请求参数
                if (paramAnnotation instanceof RequestParam) {
                    name = Optional.ofNullable(paramAnnotation).map(RequestParam.class::cast).map(RequestParam::value).orElse(parameterNames[i]);
                    urlBuilder.append(0 == i? "?" : "&")
                            .append(name)
                            .append("=")
                            .append(String.class.equals(type) ? (String) args[i] : String.valueOf(args[i]));
                } else if (paramAnnotation instanceof PathVariable) {
                    urlBuilder.replace(0, urlBuilder.length(),
                            urlBuilder.toString().replace("{" + parameterNames[i] + "}", (String) args[i]));
                }

            });
        }

        // 获取 RestTemplate
        RestTemplate restTemplate = beanFactory.getBean("loadBalanceRestTemplate", RestTemplate.class);

        return restTemplate.getForObject(urlBuilder.toString(), method.getReturnType());
    }

}
